package jvlite.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import jvlite.authority.AbstractAuthManager;
import jvlite.authority.DefaultAuthManager;
import jvlite.core.JLiteContext;

public class ProxyHandler implements InvocationHandler {

	private IAdvice advice;
	private Object target;

	public Object factory(Object target, IAdvice advice) {
		if (null == advice || "".equals(advice)) {
			this.advice = new DefaultAdvice();
		} else {
			this.advice = advice;
		}
		this.target = target;
		Class<?> cls = this.target.getClass();
		return Proxy.newProxyInstance(cls.getClassLoader(),
				cls.getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if (null == this.advice) {
			this.advice = new DefaultAdvice();
		}
		if (null == this.target) {
			throw new NullPointerException("null target");
		}
		if (null == method) {
			throw new NullPointerException("null method");
		}
		Object object = null;
		advice.beforeMethod(target);
		try {
			object = method.invoke(target, args);
		} catch (Exception e) {
			e.printStackTrace();
			advice.whenException(e);
		}
		advice.afterMethod(target);
		return object;
	}

	public Object execute(Object target, IAdvice advice, Method method,
			Object[] args) throws Throwable {
		
		if (JLiteContext.isAuthority) {
			AbstractAuthManager defAuthManager = JLiteContext.authManager;
			defAuthManager.checkAuths(target, method);
		}
		
		this.target = target;
		Object proxy = this.factory(target, advice);
		Object obj = this.invoke(proxy, method, args);
		return obj;
	}

	public Object execute(Object target, Object proxy, Method method,
			Object[] args) throws Throwable {
		if (JLiteContext.isAuthority) {
			DefaultAuthManager defAuthManager = new DefaultAuthManager();
			defAuthManager.checkAuths(target, method);
		}
		this.target = target;
		Object obj = this.invoke(proxy, method, args);
		return obj;
	}

	public IAdvice getAdvice() {
		return advice;
	}

	public void setAdvice(IAdvice advice) {
		this.advice = advice;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

}